/**
  ******************************************************************************
  * @file           : studio_vector_raster.h
  * @author         : wangyingjie
  * @brief          : 矢量光栅化, 支持在不修改范围和格点大小的情况下,
  *                   光栅化任意多个矢量,使用与列数等长的数组,记录被覆盖的格点
  *                   , 默认为0, 表示没有被覆盖, 1表示至少被覆盖一次.
                      使用fill()函数,填充成果,不会存在重复情况
  * @attention      : None
  * @date           : 2025/5/29
  ******************************************************************************
  */

#ifndef STUDIO_VECTOR_RASTER_H
#define STUDIO_VECTOR_RASTER_H

#include "studio_geo.h"
#include "studio_geo_coll.h"

class _point
{
public:
    _point() = default;

    _point(int _x, int _y)
    {
        x = _x;
        y = _y;
    }

public:
    int x{0};

    int y{0};
};

class row_pair
{
public:
    int beg = 0;
    int end = 0;
};

typedef std::map<int, std::vector<row_pair>> scan_pairs;

/// X扫描线算法

class x_scan_line
{
public:
    void set(const studio_geo_rect& rect, const double& cell_size);

    /// <summary>
    /// 光栅化单点
    /// </summary>
    /// <param name="line"></param>
    /// <returns></returns>
    void rasterize(const studio_point& point);

    /// <summary>
    /// 光栅化多点
    /// </summary>
    /// <param name="points">多点</param>
    /// <returns></returns>
    void rasterize(const studio_multi_point& points);

    /// <summary>
    /// 光栅化单线的算法, TODO: 有问题
    /// </summary>
    /// <param name="line"></param>
    /// <returns></returns>
    void rasterize(const studio_line& line);

    /// <summary>
    /// 光栅化多条线
    /// </summary>
    /// <param name="lines">多线</param>
    /// <returns></returns>
    void rasterize(const studio_multi_line& lines);

    /// <summary>
    /// 光栅化一个单点矢量
    /// </summary>
    /// <param name="poly"></param>
    /// <returns></returns>
    void rasterize(const studio_poly& poly);

    /// <summary>
    /// 光栅化一个多面矢量
    /// </summary>
    /// <param name="m_polys"></param>
    /// <returns></returns>
    void rasterize(const studio_multi_poly& m_polys);

    /// <summary>
    /// 光栅化任意一个矢量
    /// </summary>
    /// <param name="geo_coll"></param>
    /// <returns></returns>
    void rasterize(const studio_geo_coll& geo_coll);

    /// <summary>
    /// 将光栅化结果绘制到灰度图上
    /// </summary>
    /// <param name="path"></param>
    void image(const std::string& path);

    int width() const;

    int height() const;

    /// <summary>
    /// 填充pairs
    /// </summary>
    void fill();

    /// <summary>
    /// 计算得到所有扫描的块
    /// </summary>
    void blocks();

    /// <summary>
    /// 返回所有块
    /// </summary>
    std::map<int, std::vector<int>> get_blocks() const;

    scan_pairs row_pairs() const;

    /// <summary>
    /// 将光栅化结果转为网格面输出
    /// </summary>
    /// <param name="path"></param>
    std::vector<studio_poly> grids() const;

    /// <summary>
    /// 清空row_pairs
    /// </summary>
    void clear();

    // 测试使用
    // 生成所有网格的中心点
    void get_grid_mid_points(studio_multi_point& points)
    {
        // 遍历每行的 row_pairs
        for (const auto& row : m_row_pairs)
        {
            // 获取行号
            int row_idx = row.first;

            // 遍历每一对列范围
            for (const auto& pair : row.second)
            {
                int col_start = pair.beg; // 起始列
                int col_end = pair.end;   // 结束列

                // 对于该区间内的每一个栅格，计算栅格的中心点坐标
                for (int col = col_start; col <= col_end; ++col)
                {
                    // 计算栅格中心点的 X 和 Y 坐标
                    double x_center = m_rect.min.x + (col + 0.5) * m_cell_size;
                    double y_center = m_rect.max.y - (row_idx + 0.5) * m_cell_size;

                    // 创建新的 studio_point 对象并添加到 points 中
                    points.push_back(studio_point(x_center, y_center));
                }
            }
        }
    }
    // 根据格子生成中心点路径
    bool get_grad_mid_path(const std::vector<std::pair<int, int>> grad_path, studio_line& points)
    {
        bool status = false;
        if (grad_path.empty())
        {
            std::cout << "grad_path is empty" << std::endl;
            return status;
        }
        for (const auto& [row, col] : grad_path)
        {
            double x_center = m_rect.min.x + (row + 0.5) * m_cell_size;
            double y_center = m_rect.max.y - (col + 0.5) * m_cell_size;
            points.push_back(studio_point(x_center, y_center));
        }
        status = true;
        return status;
    }

private:
    /// <summary>
    /// 光栅化的基本算法, int运算效率高
    /// </summary>
    /// <param name="vertices_arr"></param>
    /// <returns></returns>
    void rasterize(const std::vector<std::vector<_point>>& vertices_arr);

    /// 计算每个点在栅格中的位置，并兼顾去重
    /// @param point 当前点
    /// @param vct 栅格中被占用的格子
    /// @param last_x 上一个点的在栅格中的x坐标
    /// @param last_y 上一个点的在栅格中的y坐标
    void check_line_point(studio_point point, std::vector<_point>& vct, int& last_x, int& last_y);

    /// <summary>
    /// 添加新的行记录,会在
    /// </summary>
    /// <returns></returns>
    void add(const int& row, const std::vector<int>& edges);

private:
    // 数据记录以经纬度左上角为原点, 向东为col的正方向,向下为row的正方向
    int m_width{0};
    int m_height{0};
    studio_geo_rect m_rect;
    // 经纬度小数点后6位能精确到1米,更加精确意义不大
    double m_cell_size{0.000001};
    // 记录每一行在矢量内的多对起始列号
    scan_pairs m_row_pairs;
    std::map<int, std::vector<int>> m_blocks; // 所有块的坐标
    std::vector<std::vector<uint8_t>> m_row_colors;
};

#endif //STUDIO_VECTOR_RASTER_H